// Copyright 2013 Beego Samples authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package controllers

import (
	"encoding/json"
	"net/http"

	"github.com/astaxie/beego"
	"github.com/gorilla/websocket"
	"gitee.com/lzqysoft/ims/models"
)

//WebSocketController 处理WebSocket请求。.
type WebSocketController struct {
	beego.Controller
}

// Message 消息获得结构
type Message struct {
	Ws  *websocket.Conn
	Evt models.WsEvent
}

//Get 获取方法处理WebSocketController的GET请求。
func (c *WebSocketController) Get() {
	// Safe check.
	username := c.GetString("username")
	roomid := c.GetString("roomid")
	if len(username) == 0 || len(roomid) == 0 {
		//		this.Data["json"] = "用户名为空！！"
		//		this.ServeJSON()
		//		return
	}
	c.Data["roomid"] = roomid
	c.Data["IsWebSocket"] = true
	c.Data["UserName"] = username
}

//Join 方法处理WebSocketController的WebSocket请求。
func (c *WebSocketController) Join() {
	//	roomid := this.GetString("roomid")
	//	userid, _ := this.GetInt64("userid")
	//	if userid < 0 || len(roomid) == 0 {
	//		this.Data["json"] = "用户名为空！！"
	//		this.ServeJSON()
	//		return
	//	}
	//从http请求升级到WebSocket。
	ws, err := websocket.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil, 1024, 1024)
	if _, ok := err.(websocket.HandshakeError); ok {
		http.Error(c.Ctx.ResponseWriter, "Not a websocket handshake", 400)
		return
	} else if err != nil {
		beego.Error("Cannot setup WebSocket connection:", err)
		return
	}
	defer ws.Close()
	// 消息接收循环。
	for {
		var evt models.WsEvent
		err := ws.ReadJSON(&evt)
		if err != nil {
			return
		}
		ms := Message{
			ws,
			evt,
		}
		publish <- ms
	}
}

// broadcastWebSocket 向WebSocket用户广播消息,只针对本房间.
func broadcastWebSocket(event models.WsEvent) {
	data, err := json.Marshal(event)
	if err != nil {
		beego.Error("Fail to marshal event:", err)
		return
	}
	for sub := subscribers.Front(); sub != nil; sub = sub.Next() {
		//立即将事件发送到WebSocket用户。
		ws := sub.Value.(Subscriber).Conn
		if ws != nil && event.RoomId == sub.Value.(Subscriber).RoomId {
			if ws.WriteMessage(websocket.TextMessage, data) != nil {
				//用户断开连接。
				unsubscribe <- sub.Value.(Subscriber)
			}
		}
	}
}

// broadcastUser 向WebSocket特定用户userid广播消息.
func broadcastUser(event models.WsEvent) {
	data, err := json.Marshal(event)
	if err != nil {
		beego.Error("Fail to marshal event:", err)
		return
	}
	for sub := subscribers.Front(); sub != nil; sub = sub.Next() {
		//立即将事件发送到WebSocket用户。
		ws := sub.Value.(Subscriber).Conn
		if ws != nil && event.UserId == sub.Value.(Subscriber).Id {
			if ws.WriteMessage(websocket.TextMessage, data) != nil {
				//用户断开连接。
				unsubscribe <- sub.Value.(Subscriber)
			}
		}
	}
}

// broadcastAll 向WebSocket所有连接用户广播消息.
func broadcastAll(event models.WsEvent) {
	data, err := json.Marshal(event)
	if err != nil {
		beego.Error("Fail to marshal event:", err)
		return
	}
	for sub := subscribers.Front(); sub != nil; sub = sub.Next() {
		//立即将事件发送到WebSocket用户。
		ws := sub.Value.(Subscriber).Conn
		if ws != nil {
			if ws.WriteMessage(websocket.TextMessage, data) != nil {
				//清空用户。
				unsubscribe <- sub.Value.(Subscriber)
			}
		}
	}
}

// Fetch 。。。
func (c *WebSocketController) Fetch() {
	lastReceived, err := c.GetInt("lastReceived")
	if err != nil {
		return
	}

	events := models.GetEvents(int64(lastReceived))
	if len(events) > 0 {
		c.Data["json"] = events
		c.ServeJSON()
		return
	}
	return
}
